﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using System.ServiceModel;
using CYTS.Aoyou.Framework.Core;
using CYTS.Aoyou.Framework.Config;

namespace CYTS.Aoyou.Framework.Service
{
    public static class ServiceFactory
    {
        private static Dictionary<Type, IService> dicTypeServiceCollection = new Dictionary<Type, IService>();
        private static object lockObj = new object();

        static ServiceFactory()
        {
            ConfigFactory.OnModified += new Action(ConfigFactory_OnModified);
        }

        public static TInterface GetInstance<TInterface>() where TInterface : class, IService
        {
            Type type = typeof(TInterface);
            IService service = null;
            if (!dicTypeServiceCollection.TryGetValue(type, out service))
            {
                lock (lockObj)
                {
                    if (!dicTypeServiceCollection.TryGetValue(type, out service))
                    {
                        Binding binding = null;
                        EndpointAddress address = null;
                        ServiceClientConfig clientConfig = ConfigFactory.GetConfig<ServiceClientConfig>();
                        if (clientConfig.Client == null)
                        {
                            throw new Exception("配置文件关键元素缺失");
                        }

                        ClientEndpoint endpointConfig = clientConfig.Client.FirstOrDefault(p => p.Contract.ToLower() == type.FullName.ToLower());
                        if (endpointConfig == null)
                        {
                            throw new Exception("未找到ClientEndpoint对应的配置: " + type.FullName);
                        }

                        binding = GetBinding(endpointConfig);
                        address = new EndpointAddress(endpointConfig.Address);

                        if (binding == null)
                        {
                            throw new Exception(type.FullName + "未找到匹配的ClientEndpoint的绑定");
                        }

                        Type typeProxy = TypeBuilder.BuildType<TInterface, ChannelFactoryTypeGenerator<TInterface>>();
                        service = (TInterface)Activator.CreateInstance(typeProxy, binding, address);
                        dicTypeServiceCollection[type] = service;
                    }
                }
            }

            //ICommunicationObject co = (ICommunicationObject)service;
            //if (co.State == CommunicationState.Closed || co.State == CommunicationState.Faulted)
            //{
            //    dicTypeServiceCollection.Remove(type);
            //    return GetInstance<TInterface>();
            //}

            return (TInterface)service;
        }


        public static void Remove<TInterface>()
        {
            Type type = typeof(TInterface);
            lock (lockObj)
            {
                dicTypeServiceCollection.Remove(type);
            }
        }

        public static void RemoveAll()
        {
            lock (lockObj)
            {
                dicTypeServiceCollection.Clear();
            }
        }

        public static IList<IService> GetAllServiceListInMemory()
        {
            return dicTypeServiceCollection.Values.ToList();
        }

        private static Binding GetBinding(ClientEndpoint endpointConfig)
        {
            Binding binding = null;

            switch (endpointConfig.Binding)
            {
                case "basicHttpBinding":
                    BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
                    basicHttpBinding.MaxReceivedMessageSize = endpointConfig.MaxReceivedMessageSize;
                    basicHttpBinding.ReaderQuotas.MaxStringContentLength = endpointConfig.MaxStringContentLength;
                    binding = basicHttpBinding;
                    break;

                case "netMsmqBinding":
                    NetMsmqBinding netMsmqBinding = new NetMsmqBinding(NetMsmqSecurityMode.None);
                    netMsmqBinding.MaxReceivedMessageSize = endpointConfig.MaxReceivedMessageSize;
                    netMsmqBinding.ReaderQuotas.MaxStringContentLength = endpointConfig.MaxStringContentLength;
                    binding = netMsmqBinding;
                    break;

                case "wsHttpBinding":
                    WSHttpBinding wsHttpBinding = new WSHttpBinding(SecurityMode.None);
                    wsHttpBinding.MaxReceivedMessageSize = endpointConfig.MaxReceivedMessageSize;
                    wsHttpBinding.ReaderQuotas.MaxStringContentLength = endpointConfig.MaxStringContentLength;
                    binding = wsHttpBinding;
                    break;

                case "netTcpBinding":
                    NetTcpBinding netTcpBinding = new NetTcpBinding(SecurityMode.None);
                    netTcpBinding.MaxReceivedMessageSize = endpointConfig.MaxReceivedMessageSize;
                    netTcpBinding.ReaderQuotas.MaxStringContentLength = endpointConfig.MaxStringContentLength;
                    binding = netTcpBinding;
                    break;
            }

            if (binding == null)
            {
                throw new Exception("服务配置了不识别的" + endpointConfig.Binding);
            }


            //设置超时时间
            binding.SendTimeout = endpointConfig.SendTimeout;
            binding.OpenTimeout = endpointConfig.OpenTimeout;
            binding.CloseTimeout = endpointConfig.CloseTimeout;
            binding.ReceiveTimeout = endpointConfig.ReceiveTimeout;

            return binding;
        }

        static void ConfigFactory_OnModified()
        {
            lock (lockObj)
            {
                dicTypeServiceCollection.Clear();
            }
        }
    }
}
